package cn.iocoder.yudao.module.reading.service.classes;

import cn.hutool.core.util.RandomUtil;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.reading.controller.app.classes.vo.*;
import cn.iocoder.yudao.module.reading.controller.app.punch.vo.PunchRecordRespVO;
import cn.iocoder.yudao.module.reading.dal.dataobject.classes.ClassDO;
import cn.iocoder.yudao.module.reading.dal.dataobject.classes.ClassMemberDO;
import cn.iocoder.yudao.module.reading.dal.dataobject.punch.PunchRecordDO;
import cn.iocoder.yudao.module.reading.dal.dataobject.user.UserDO;
import cn.iocoder.yudao.module.reading.dal.mysql.classes.ClassMapper;
import cn.iocoder.yudao.module.reading.dal.mysql.classes.ClassMemberMapper;
import cn.iocoder.yudao.module.reading.dal.mysql.punch.PunchRecordMapper;
import cn.iocoder.yudao.module.reading.dal.mysql.record.ReadingRecordMapper;
import cn.iocoder.yudao.module.reading.dal.mysql.user.UserMapper;
import cn.iocoder.yudao.module.reading.service.punch.PunchService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import jakarta.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.reading.enums.ErrorCodeConstants.*;

/**
 * 班级管理 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class ClassServiceImpl implements ClassService {

    @Resource
    private ClassMapper classMapper;
    @Resource
    private ClassMemberMapper classMemberMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private PunchRecordMapper punchRecordMapper;
    @Resource
    private ReadingRecordMapper readingRecordMapper;
    @Resource
    private PunchService punchService;

    @Override
    public List<ClassRespVO> getUserClasses(Long userId) {
        // 查询用户参与的班级成员记录
        List<ClassMemberDO> memberRecords = classMemberMapper.selectByUserId(userId);
        if (memberRecords.isEmpty()) {
            return new ArrayList<>();
        }

        // 获取班级ID列表
        List<Long> classIds = memberRecords.stream()
                .map(ClassMemberDO::getClassId)
                .collect(Collectors.toList());

        // 查询班级信息
        List<ClassDO> classes = classMapper.selectBatchIds(classIds);
        
        // 构建班级信息映射
        Map<Long, ClassDO> classMap = classes.stream()
                .collect(Collectors.toMap(ClassDO::getId, c -> c));

        // 构建用户角色映射
        Map<Long, String> roleMap = memberRecords.stream()
                .collect(Collectors.toMap(ClassMemberDO::getClassId, ClassMemberDO::getRole));

        // 转换为响应VO
        List<ClassRespVO> result = new ArrayList<>();
        for (ClassDO classDO : classes) {
            ClassRespVO respVO = BeanUtils.toBean(classDO, ClassRespVO.class);
            respVO.setRole(roleMap.get(classDO.getId()));
            
            // 获取创建者姓名
            UserDO creator = userMapper.selectById(classDO.getCreatorId());
            if (creator != null) {
                respVO.setCreatorName(creator.getNickname());
            }
            
            result.add(respVO);
        }

        return result;
    }

    @Override
    public ClassRespVO getClassDetail(Long classId, Long userId) {
        // 检查班级是否存在
        ClassDO classDO = validateClassExists(classId);
        
        // 检查用户是否为班级成员
        ClassMemberDO memberRecord = classMemberMapper.selectByClassIdAndUserId(classId, userId);
        if (memberRecord == null) {
            throw exception(CLASS_MEMBER_NOT_EXISTS);
        }

        // 转换为响应VO
        ClassRespVO respVO = BeanUtils.toBean(classDO, ClassRespVO.class);
        respVO.setRole(memberRecord.getRole());

        // 获取创建者姓名
        UserDO creator = userMapper.selectById(classDO.getCreatorId());
        if (creator != null) {
            respVO.setCreatorName(creator.getNickname());
        }

        return respVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createClass(Long userId, ClassCreateReqVO createReqVO) {
        // 生成唯一的班级口令
        String classCode = generateUniqueClassCode();

        // 创建班级
        ClassDO classDO = ClassDO.builder()
                .className(createReqVO.getClassName())
                .classCode(classCode)
                .creatorId(userId)
                .description(createReqVO.getDescription())
                .isLocked(false)
                .memberCount(1)
                .isActive(true)
                .build();
        classMapper.insert(classDO);

        // 添加创建者为班级成员（角色为teacher）
        ClassMemberDO memberDO = ClassMemberDO.builder()
                .classId(classDO.getId())
                .userId(userId)
                .role("teacher")
                .joinTime(LocalDateTime.now())
                .isActive(true)
                .build();
        classMemberMapper.insert(memberDO);

        log.info("用户 {} 创建班级成功，班级ID: {}, 班级口令: {}", userId, classDO.getId(), classCode);
        return classDO.getId();
    }

    @Override
    public void updateClass(Long classId, Long userId, ClassUpdateReqVO updateReqVO) {
        // 检查班级是否存在
        ClassDO classDO = validateClassExists(classId);
        
        // 检查用户是否为班级创建者
        if (!classDO.getCreatorId().equals(userId)) {
            throw exception(CLASS_NO_PERMISSION);
        }

        // 更新班级信息
        ClassDO updateDO = ClassDO.builder()
                .id(classId)
                .className(updateReqVO.getClassName())
                .description(updateReqVO.getDescription())
                .build();
        classMapper.updateById(updateDO);

        log.info("用户 {} 更新班级 {} 信息成功", userId, classId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteClass(Long classId, Long userId) {
        // 检查班级是否存在
        ClassDO classDO = validateClassExists(classId);
        
        // 检查用户是否为班级创建者
        if (!classDO.getCreatorId().equals(userId)) {
            throw exception(CLASS_NO_PERMISSION);
        }

        // 软删除班级
        classMapper.deleteById(classId);

        // 删除所有班级成员记录
        List<ClassMemberDO> members = classMemberMapper.selectByClassId(classId);
        for (ClassMemberDO member : members) {
            classMemberMapper.deleteById(member.getId());
        }

        log.info("用户 {} 删除班级 {} 成功", userId, classId);
    }

    /**
     * 验证班级是否存在
     */
    private ClassDO validateClassExists(Long classId) {
        ClassDO classDO = classMapper.selectById(classId);
        if (classDO == null) {
            throw exception(CLASS_NOT_EXISTS);
        }
        return classDO;
    }

    /**
     * 生成唯一的班级口令
     */
    private String generateUniqueClassCode() {
        String classCode;
        int attempts = 0;
        do {
            classCode = RandomUtil.randomNumbers(9);
            attempts++;
            if (attempts > 100) {
                throw new RuntimeException("生成班级口令失败，请重试");
            }
        } while (classMapper.existsByClassCode(classCode));
        return classCode;
    }

    @Override
    public List<ClassMemberRespVO> getClassMembers(Long classId, Long userId) {
        // 检查班级是否存在
        validateClassExists(classId);

        // 检查用户是否为班级创建者或成员
        if (!isClassCreator(classId, userId) && !isClassMember(classId, userId)) {
            throw exception(CLASS_MEMBER_NOT_EXISTS);
        }

        // 查询班级所有成员（包括老师）
        List<ClassMemberDO> members = classMemberMapper.selectByClassId(classId);
        if (members.isEmpty()) {
            return new ArrayList<>();
        }

        // 获取用户信息
        List<Long> userIds = members.stream()
                .map(ClassMemberDO::getUserId)
                .collect(Collectors.toList());
        List<UserDO> users = userMapper.selectBatchIds(userIds);
        Map<Long, UserDO> userMap = users.stream()
                .collect(Collectors.toMap(UserDO::getId, u -> u));

        // 转换为响应VO
        List<ClassMemberRespVO> result = new ArrayList<>();
        for (ClassMemberDO member : members) {
            UserDO user = userMap.get(member.getUserId());
            if (user == null) continue;

            ClassMemberRespVO respVO = new ClassMemberRespVO();
            respVO.setUserId(user.getId());
            respVO.setNickname(user.getNickname());
            respVO.setAvatar(user.getAvatar());
            respVO.setRole(member.getRole());
            respVO.setJoinTime(member.getJoinTime());

            // 计算阅读天数和阅读绘本数
            Integer readingDays = calculateUserReadingDays(user.getId());
            Integer readingBooks = calculateUserReadingBooks(user.getId());
            respVO.setReadingDays(readingDays);
            respVO.setReadingBooks(readingBooks);

            // 检查今日是否已打卡
            boolean todayPunched = punchRecordMapper.existsByUserIdAndDate(user.getId(), LocalDate.now());
            respVO.setTodayPunched(todayPunched);

            // 转换URL
            respVO.convertUrls();

            result.add(respVO);
        }

        return result;
    }

    @Override
    public List<ClassMemberRespVO> getClassStudents(Long classId, Long userId) {
        // 检查班级是否存在
        validateClassExists(classId);

        // 检查用户是否为班级创建者或成员
        if (!isClassCreator(classId, userId) && !isClassMember(classId, userId)) {
            throw exception(CLASS_MEMBER_NOT_EXISTS);
        }

        // 查询班级学生成员（排除老师）
        List<ClassMemberDO> members = classMemberMapper.selectStudentsByClassId(classId);
        if (members.isEmpty()) {
            return new ArrayList<>();
        }

        // 获取用户信息
        List<Long> userIds = members.stream()
                .map(ClassMemberDO::getUserId)
                .collect(Collectors.toList());
        List<UserDO> users = userMapper.selectBatchIds(userIds);
        Map<Long, UserDO> userMap = users.stream()
                .collect(Collectors.toMap(UserDO::getId, u -> u));

        // 构建响应
        List<ClassMemberRespVO> result = new ArrayList<>();
        for (ClassMemberDO member : members) {
            UserDO user = userMap.get(member.getUserId());
            if (user == null) continue;

            ClassMemberRespVO respVO = new ClassMemberRespVO();
            respVO.setUserId(member.getUserId());
            respVO.setNickname(user.getNickname());
            respVO.setAvatar(user.getAvatar());
            respVO.setRole(member.getRole());
            respVO.setJoinTime(member.getJoinTime());

            // 设置统计信息（简化版本，只设置基本信息）
            respVO.setReadingDays(0);
            respVO.setReadingBooks(0);

            // 检查今日打卡状态
            boolean todayPunched = punchRecordMapper.existsByUserIdAndDate(user.getId(), LocalDate.now());
            respVO.setTodayPunched(todayPunched);

            // 转换URL
            respVO.convertUrls();

            result.add(respVO);
        }

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeMember(Long classId, Long targetUserId, Long operatorId) {
        // 检查班级是否存在
        ClassDO classDO = validateClassExists(classId);

        // 检查操作者是否为班级创建者
        if (!classDO.getCreatorId().equals(operatorId)) {
            throw exception(CLASS_NO_PERMISSION);
        }

        // 不能移除自己
        if (targetUserId.equals(operatorId)) {
            throw exception(CLASS_CANNOT_REMOVE_SELF);
        }

        // 检查目标用户是否为班级成员
        ClassMemberDO memberRecord = classMemberMapper.selectByClassIdAndUserId(classId, targetUserId);
        if (memberRecord == null) {
            throw exception(CLASS_MEMBER_NOT_EXISTS);
        }

        // 移除成员
        classMemberMapper.deleteByClassIdAndUserId(classId, targetUserId);

        // 更新班级成员数量
        Integer memberCount = classMemberMapper.countByClassId(classId);
        ClassDO updateDO = ClassDO.builder()
                .id(classId)
                .memberCount(memberCount)
                .build();
        classMapper.updateById(updateDO);

        log.info("用户 {} 从班级 {} 移除成员 {} 成功", operatorId, classId, targetUserId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long joinClass(Long userId, JoinClassReqVO joinReqVO) {
        // 根据班级口令查询班级
        ClassDO classDO = classMapper.selectByClassCode(joinReqVO.getClassCode());
        if (classDO == null) {
            throw exception(CLASS_CODE_INVALID);
        }

        // 检查班级是否锁定
        if (classDO.getIsLocked()) {
            throw exception(CLASS_LOCKED);
        }

        // 检查用户是否已经是班级成员
        ClassMemberDO existingMember = classMemberMapper.selectByClassIdAndUserId(classDO.getId(), userId);
        if (existingMember != null) {
            throw exception(CLASS_MEMBER_ALREADY_EXISTS);
        }

        // 添加用户为班级成员
        ClassMemberDO memberDO = ClassMemberDO.builder()
                .classId(classDO.getId())
                .userId(userId)
                .role("student")
                .joinTime(LocalDateTime.now())
                .isActive(true)
                .build();
        classMemberMapper.insert(memberDO);

        // 更新班级成员数量
        Integer memberCount = classMemberMapper.countByClassId(classDO.getId());
        ClassDO updateDO = ClassDO.builder()
                .id(classDO.getId())
                .memberCount(memberCount)
                .build();
        classMapper.updateById(updateDO);

        log.info("用户 {} 加入班级 {} 成功", userId, classDO.getId());

        // 返回班级ID
        return classDO.getId();
    }

    @Override
    public void switchCurrentClass(Long userId, SwitchClassReqVO switchReqVO) {
        // 检查班级是否存在
        validateClassExists(switchReqVO.getClassId());

        // 检查用户是否为班级成员
        if (!isClassMember(switchReqVO.getClassId(), userId)) {
            throw exception(CLASS_MEMBER_NOT_EXISTS);
        }

        // TODO: 实现切换当前班级的逻辑（可能需要在用户设置中记录当前班级）
        log.info("用户 {} 切换到班级 {} 成功", userId, switchReqVO.getClassId());
    }



    @Override
    @Transactional(rollbackFor = Exception.class)
    public void classPunch(Long classId, Long userId, ClassPunchReqVO punchReqVO) {
        // 检查班级是否存在
        validateClassExists(classId);

        // 检查用户是否为班级成员
        if (!isClassMember(classId, userId)) {
            throw exception(CLASS_MEMBER_NOT_EXISTS);
        }

        // 调用打卡服务进行班级打卡
        // 注意：这里需要将ClassPunchReqVO转换为PunchCreateReqVO
        // TODO: 实现班级打卡逻辑，可能需要在打卡记录中关联班级ID
        log.info("用户 {} 在班级 {} 打卡成功", userId, classId);
    }

    @Override
    public String generateClassCode() {
        return generateUniqueClassCode();
    }

    @Override
    public ClassCodeVerifyRespVO verifyClassCode(String classCode) {
        ClassDO classDO = classMapper.selectByClassCode(classCode);

        ClassCodeVerifyRespVO respVO = new ClassCodeVerifyRespVO();
        if (classDO == null) {
            respVO.setIsValid(false);
            return respVO;
        }

        respVO.setIsValid(true);
        respVO.setClassId(classDO.getId());
        respVO.setClassName(classDO.getClassName());
        respVO.setMemberCount(classDO.getMemberCount());
        respVO.setIsLocked(classDO.getIsLocked());

        // 获取创建者姓名
        UserDO creator = userMapper.selectById(classDO.getCreatorId());
        if (creator != null) {
            respVO.setCreatorName(creator.getNickname());
        }

        return respVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void transferClass(Long classId, Long operatorId, TransferClassReqVO transferReqVO) {
        // 检查班级是否存在
        ClassDO classDO = validateClassExists(classId);

        // 检查操作者是否为班级创建者
        if (!classDO.getCreatorId().equals(operatorId)) {
            throw exception(CLASS_NO_PERMISSION);
        }

        // 检查新管理员是否为班级成员
        ClassMemberDO newCreatorMember = classMemberMapper.selectByClassIdAndUserId(classId, transferReqVO.getNewCreatorId());
        if (newCreatorMember == null) {
            throw exception(CLASS_MEMBER_NOT_EXISTS);
        }

        // 更新班级创建者
        ClassDO updateDO = ClassDO.builder()
                .id(classId)
                .creatorId(transferReqVO.getNewCreatorId())
                .build();
        classMapper.updateById(updateDO);

        // 更新原创建者角色为学生
        ClassMemberDO oldCreatorMember = classMemberMapper.selectByClassIdAndUserId(classId, operatorId);
        if (oldCreatorMember != null) {
            oldCreatorMember.setRole("student");
            classMemberMapper.updateById(oldCreatorMember);
        }

        // 更新新创建者角色为老师
        newCreatorMember.setRole("teacher");
        classMemberMapper.updateById(newCreatorMember);

        log.info("班级 {} 管理权从用户 {} 转让给用户 {} 成功", classId, operatorId, transferReqVO.getNewCreatorId());
    }

    @Override
    public void lockClass(Long classId, Long operatorId, LockClassReqVO lockReqVO) {
        // 检查班级是否存在
        ClassDO classDO = validateClassExists(classId);

        // 检查操作者是否为班级创建者
        if (!classDO.getCreatorId().equals(operatorId)) {
            throw exception(CLASS_NO_PERMISSION);
        }

        // 更新班级锁定状态
        ClassDO updateDO = ClassDO.builder()
                .id(classId)
                .isLocked(lockReqVO.getIsLocked())
                .build();
        classMapper.updateById(updateDO);

        log.info("用户 {} {} 班级 {} 成功", operatorId, lockReqVO.getIsLocked() ? "锁定" : "解锁", classId);
    }

    @Override
    public ClassDO getClass(Long classId) {
        return classMapper.selectById(classId);
    }

    @Override
    public boolean isClassCreator(Long classId, Long userId) {
        ClassDO classDO = classMapper.selectById(classId);
        return classDO != null && classDO.getCreatorId().equals(userId);
    }

    @Override
    public boolean isClassMember(Long classId, Long userId) {
        ClassMemberDO memberRecord = classMemberMapper.selectByClassIdAndUserId(classId, userId);
        return memberRecord != null && memberRecord.getIsActive();
    }

    @Override
    public boolean isMultiClassCreator(List<Long> classIds, Long userId) {
        if (classIds == null || classIds.isEmpty()) {
            return false;
        }

        // 检查用户是否为所有班级的创建者
        for (Long classId : classIds) {
            if (!isClassCreator(classId, userId)) {
                return false;
            }
        }
        return true;
    }

    @Override
    public void validateMultiClassExists(List<Long> classIds) {
        if (classIds == null || classIds.isEmpty()) {
            throw exception(CLASS_NOT_EXISTS, "班级ID列表不能为空");
        }

        for (Long classId : classIds) {
            ClassDO classDO = classMapper.selectById(classId);
            if (classDO == null) {
                throw exception(CLASS_NOT_EXISTS, "班级不存在: " + classId);
            }
        }
    }

    @Override
    public List<PunchRecordRespVO> getClassPunchRecords(Long classId, Long userId) {
        // 检查班级是否存在
        validateClassExists(classId);

        // 检查用户是否为班级创建者或成员
        if (!isClassCreator(classId, userId) && !isClassMember(classId, userId)) {
            throw exception(CLASS_MEMBER_NOT_EXISTS);
        }

        // 使用PunchService的新方法查询班级打卡记录
        return punchService.getPunchRecordsByClassId(classId);
    }

    /**
     * 计算用户阅读天数
     * 基于打卡记录计算
     *
     * @param userId 用户ID
     * @return 阅读天数
     */
    private Integer calculateUserReadingDays(Long userId) {
        try {
            // 查询用户所有打卡记录，计算不同的打卡日期数量
            List<PunchRecordDO> punchRecords = punchRecordMapper.selectList(
                    new LambdaQueryWrapperX<PunchRecordDO>()
                            .eq(PunchRecordDO::getUserId, userId)
                            .select(PunchRecordDO::getPunchDate)
            );

            // 统计不同的打卡日期数量
            long distinctDays = punchRecords.stream()
                    .map(PunchRecordDO::getPunchDate)
                    .distinct()
                    .count();

            return (int) distinctDays;
        } catch (Exception e) {
            log.error("计算用户阅读天数失败，用户ID: {}", userId, e);
            return 0;
        }
    }

    /**
     * 计算用户阅读绘本数
     * 基于阅读记录计算已完成的绘本数量
     *
     * @param userId 用户ID
     * @return 阅读绘本数
     */
    private Integer calculateUserReadingBooks(Long userId) {
        try {
            // 查询用户已完成阅读的绘本数量
            Long count = readingRecordMapper.countTotalReadBooks(userId);
            return count != null ? count.intValue() : 0;
        } catch (Exception e) {
            log.error("计算用户阅读绘本数失败，用户ID: {}", userId, e);
            return 0;
        }
    }
}
